package com.synjones.pay.model.context;

import java.util.*;

/*
 * extend Hash Map to provide case insensitive
 */
@SuppressWarnings("serial")
public final class HashMapCaseInsensitive<T> extends HashMap<String, T> 
{
	// save mapping between original key and internal key
	private HashMap<String, String> _keyMapping;

	// locale maybe is useful
	private Locale _locale;

	private final static int _defaultCapacity = 128;

	public HashMapCaseInsensitive() 
	{
		this(null, Locale.getDefault());
	}

	public HashMapCaseInsensitive(Locale locale) 
	{
		this(null, locale);
	}

	public HashMapCaseInsensitive(Map<String, T> map) 
	{
		this(map, Locale.getDefault());
	}

	public HashMapCaseInsensitive(Map<String, T> map, Locale locale) 
	{
		super(_defaultCapacity);
		this._locale = locale;
		importKeyMapping(map);
	}

	private void importKeyMapping(Map<String, T> map)
	{
		this._keyMapping = new HashMap<String, String>();
		
		if( map != null)
			super.putAll(map);
		
		
		/* fragment of putAll implement:
		 * for (Iterator<? extends Map.Entry<? extends K, ? extends V>> i = m.entrySet().iterator(); i.hasNext(); ) 
		 * {
		 * 		Map.Entry<? extends K, ? extends V> e = i.next();
		 * 		put(e.getKey(), e.getValue());   <-- !!! be override listed below
		 * }
         */
	}

	private String getKey(String key) 
	{
		return key.toLowerCase(this._locale);
	}

	@Override
	public T put(String key, T value) 
	{
		this._keyMapping.put(getKey(key), key);
		return super.put(key, value);
	}

	@Override
	public boolean containsKey(Object key) 
	{
		if (!(key instanceof String))
			return false;

		return this._keyMapping.containsKey(getKey((String) key));
	}

	@Override
	public T get(Object key)
	{
		if (!(key instanceof String))
			return null;

		String k = getKey((String) key);

		return super.get(this._keyMapping.get(k));
	}

	@Override
	public T remove(Object key) 
	{
		if (!(key instanceof String))
			return null;

		String k = getKey((String) key);

		// remove key mapping
		this._keyMapping.remove(k);

		// remove <key,value> indeed
		return super.remove(key);
	}

	@Override
	public void clear() 
	{
		this._keyMapping.clear();
		super.clear();
	}
}
